#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "sys/socket.h"
#include "unistd.h"
#include "arpa/inet.h"

#include "connect.h"

int mqtt_connect( )
{
    unsigned char flags = 0x00;
	unsigned char *packet = NULL;
	unsigned short packet_length = 0;	
	unsigned short clientidlen = strlen(CLIENT_ID);
	unsigned short usernamelen = strlen(USER_NAME);
	unsigned short passwordlen = strlen(USER_PASSWD);

    //unsigned short usernamelen = 0;
    //passwordlen = 0;

	unsigned short payload_len = clientidlen + 2;
	// Variable header
	unsigned char var_header[10] = 
    {
		0x00,0x04,/*len*/
        0x4d,0x51,0x54,0x54,/*mqtt*/
		0x04,/*协议版本*/
    };
	
	unsigned char fixedHeaderSize = 2;    // Default size = one byte Message Type + one byte Remaining Length
	unsigned char remainLen = 0;
	unsigned char *fixed_header = NULL;
	unsigned short offset = 0;
    
	if(config_tcp_socket_connect() == -1)//先建立TCP套接字
    {
        return -1;
    }

	int sockfd = config_get_cur_socket(); //获得建立好的套接字

	if(sockfd == -1)
	{
		printf("%s():invalid socket\n",__func__);
		return -1;
	}

	//printf("%s():start\n",__func__);
	
	// Preparing the flags
    /*用户名长度(可选)*/
	if(usernamelen) 
    { 
		payload_len += usernamelen + 2;
		flags |= MQTT_USERNAME_FLAG;/*或上用户名标记*/
	}
    
    /*用户密码(可选)*/
	if(passwordlen) 
    { 
		payload_len += passwordlen + 2;
		flags |= MQTT_PASSWORD_FLAG;/*用户密码标记位*/
	}

	flags |= MQTT_CLEAN_SESSION;

	var_header[7] = flags;/*连接标记*/
	var_header[8] = KEEP_ALIVE>>8;/*保持连接字段，占用两个字节*/
	var_header[9] = KEEP_ALIVE&0xFF;

	remainLen = sizeof(var_header)+payload_len; /*剩余长度，也就是可变报头加上负载的长度*/

    //printf("mqtt_connect():remainlen is %d,var_header len is %ld,payload len is %d\n",\
    //        remainLen,sizeof(var_header),payload_len);

	if (remainLen > 127) 
    {
	    fixedHeaderSize++;// add an additional byte for Remaining Length          
	}
   
	fixed_header = (unsigned char *)malloc(fixedHeaderSize); /*固定报头*/
	// Message Type
	*fixed_header = MQTT_MSG_CONNECT;/*报文类型,connect*/

	// Remaining Length,剩余长度计算，可变长编码
	if (remainLen <= 127) 
    {
	    *(fixed_header+1) = remainLen;
	} else {
	    // first byte is remainder (mod) of 128, then set the MSB to indicate more bytes
	    *(fixed_header+1) = remainLen % 128;
	    *(fixed_header+1) = *(fixed_header+1) | 0x80;
	    // second byte is number of 128s
	    *(fixed_header+2) = remainLen / 128;
	}

	packet_length = fixedHeaderSize+sizeof(var_header)+payload_len;/*固定报头+可变报头+负载长度*/
	packet = (unsigned char *)malloc(packet_length);/*分配内存*/
	memset(packet, 0, packet_length);
	memcpy(packet, fixed_header, fixedHeaderSize);/*填充固定报头*/
	free(fixed_header);	
	offset += fixedHeaderSize;
	memcpy(packet+offset, var_header, sizeof(var_header));/*填充可变报头*/
	offset += sizeof(var_header);
	
	packet[offset++] = clientidlen>>8;// Client ID - UTF encoded,填充clientid长度+clientid
	packet[offset++] = clientidlen&0xFF;
	memcpy(packet+offset, CLIENT_ID, clientidlen);
	offset += clientidlen;

	if(usernamelen) {// Username - UTF encoded,填充用户名+用户名长度
		packet[offset++] = usernamelen>>8;
		packet[offset++] = usernamelen&0xFF;
		memcpy(packet+offset, USER_NAME, usernamelen);
		offset += usernamelen;
	}

	if(passwordlen) {// Password - UTF encoded,填充用户密码+用户名密码长度
		packet[offset++] = passwordlen>>8;
		packet[offset++] = passwordlen&0xFF;
		memcpy(packet+offset, USER_PASSWD, passwordlen);
		offset += passwordlen;
	}

	//config_printf_hex(packet,packet_length);//for debug

	// Send the packet
    if(config_mqtt_write(sockfd,packet,packet_length) < 0)
    {
        printf("%s：failed\n",__func__);
         free(packet);
        return -1;
    }

    free(packet);
	return 1;
}

void mqtt_disconnect(int socket)
{
    char frame[50]={0};

    memset(frame,0,sizeof(frame));

    //心跳帧,保留位为空
    frame[0] = MQTT_MSG_DISCONNECT;
    frame[1] = 0; //剩余长度为0

    //无可变报头,无有效载荷
    config_mqtt_write(config_get_cur_socket(),frame,2);
	config_set_connect_sta(NETSTA_CONN_SOCKET);
	config_tcp_socket_disconnect(socket);
	config_set_connect_sta(NETSTA_NONE);
}

